﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Drawing;



namespace HA.Data
{

    /// <summary>
    /// 生成等值线的算法，选项
    /// </summary>
    [Serializable]
   public class ContourBuildOption
    {

        /// <summary>
        /// 
        /// </summary>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <param name="rampColor"></param>
        /// <param name="precision">保留到第几位数字</param>
        public ContourBuildOption(double min, double max, List<Color> rampColor)
        {

            this._min = min;
            this._max = max;

            this._rampColors = rampColor;
        }


        double _min;

        /// <summary>
        /// 要求生成等值线的最小值
        /// </summary>
        public double Min
        {
            get { return _min; }
            set { _min = value; }
        }


        double _max;

        /// <summary>
        /// 要求生成等值线的最大值
        /// </summary>
        public double Max
        {
            get { return _max; }
            set { _max = value; }
        }


        List<Color> _rampColors;

        public List<Color> RampColors
        {
            get { return _rampColors; }
            set { _rampColors = value; }
        }

        int _precision = 1;

        public int Precision
        {
            get { return _precision; }
            set { _precision = value; }
        }

        /// <summary>
        /// 根据最大最小值和间距生成  具体的距离算法
        /// </summary>
        /// <param name="distance"></param>
        /// <returns></returns>
        protected List<double> BuildWithDistance(double distance)
        {
           
            List<double> result = new List<double>();

            if (this._min == this._max)
            {
                result.Add(this._min);
            }
            else
            {
                for (double i = this._min; i <= this._max; i += distance)
                {
                    result.Add(i);
                }
                ////最后一个值，需要有所变化，变化成最大值？
                //if (result.Count >0)
                //{
                //    result[result.Count - 1] = this._max;                 
                //}
                //result.Add(this._max);
            }

            return result;
 
        }


        protected List<double> BuildWithCount(int count)
        {

            double distance = (double)((double)(this.Max - this.Min)) / (count - 1);

            return this.BuildWithDistance(distance);
 
        }



        protected List<Color> BuildColorRamp(List<Color> color,int n)
        {

            List<Color> result = new List<Color>();


            double dsub = (double)(double)n / (double)(color.Count - 1);

            int nSub =(int)Math.Ceiling(dsub);


            for (int i = 0; i < color.Count-1; i++)
            {

                Color col1 = color[i];

                Color col2 = color[i+1];

              result.AddRange(this.BuildColorRamp(col1,col2,nSub));

            }


            return result;
           





 
        }




        protected List<Color> BuildColorRamp(Color col1, Color col2,int n)
        {




            List<Color> result = new List<Color>();


            //这个算法是自己想的，不知道对不对啊


            double dR = (col2.R - col1.R)/(double)(n-1);

            double dG = (col2.G - col1.G)/ (double)(n - 1);

            double dB =( col2.B - col1.B) / (double)(n - 1);


            result.Add(col1);



            for (int i = 1; i < n-1; i++)
            {

              Color colItem=   Color.FromArgb((int)(col1.R+dR*i),(int)(col1.G+dG*i),(int)(col1.B+dB*i));



              result.Add(colItem);



            }

            result.Add(col2);


            return result;


 

        }



        public Color GetColor(double value, List<Color> colors)
        {

            //取得对应的比例

            int index=0;

            if (value<=this.Min)
            {
                index = 0;
                
            }

            if (value>=this.Max)
            {
                index = colors.Count - 1;
                
            }

            if (value<Max&&value>Min)
            {
                double percent = (value - this.Min) / (this.Max - this.Min);

                index = (int)(percent *(colors.Count - 1));

                
            }

            

            



            return colors[index];
            




        }


        /// <summary>
        /// 等值线调用的主函数
        /// </summary>
        /// <param name="count">个数</param>
        /// <param name="precision">位数</param>
        /// <param name="isRound">保留多少位数值标志,默认否</param>
        /// <returns></returns>
        public List<LinearContourColorValue> BuildCountourLineWithCount(int count, int precision, bool isRound, ref int noSpecificPrecision)
        {

            List<LinearContourColorValue> result = new List<LinearContourColorValue>();



            List<double> lines =  this.BuildWithCount(count);

            if (lines!=null )
            {
                if (lines .Count <count)
                {
                    lines.Add(this._max );
                }
            }


            int maxNumber = 15;

            if (isRound == false && lines != null)
            {
                maxNumber = 0;
                for (int i = 0; i < lines.Count; i++)
                {
                   
                    int len = GetDecimalLengthInDoubleValue(lines[i]);

                    if (len > maxNumber)
                    {
                        maxNumber = len;
                    }
                }
            }
            noSpecificPrecision = maxNumber;


            //生成300个颜色集锦

            List<Color> rampColors = this.BuildColorRamp(this._rampColors,300);

            foreach (double line in lines)
            {
                LinearContourColorValue cline = new LinearContourColorValue();
                if (isRound)
                {
                    cline.Value = Math.Round(line, precision);
                }
                else
                {
                    //cline.Value = line;
                    cline.Value = Math.Round(line, maxNumber);
                }


                //cline.Color = this.GetColor(line,rampColors);
                cline.Color = this.GetColor(cline.Value, rampColors);

                result.Add(cline);
                
            }



            if (isRound)
            {
                ChangeDataRange(result, precision);
            }
            else
            {
                ChangeDataRange(result, maxNumber);
            }


            //排序 去同

           return  SortAndRemoveSameValue(result);


            //return result;

 

        }

        /// <summary>
        /// 根据距离算
        /// </summary>
        /// <param name="distance"></param>
        /// <param name="precision">位数</param>
        /// <param name="isRound">保留有效数字标志，默认否</param>
        /// <returns></returns>
        public List<LinearContourColorValue> BuildContourLineWithDistance(double distance, int precision, bool isRound,ref int noSpecificPrecision)
        {

            List<LinearContourColorValue> result = new List<LinearContourColorValue>();



            List<double> lines = this.BuildWithDistance(distance);


            if (lines !=null )
            {
                if (lines .Count >0)
                {
                    if (lines [lines.Count  -1]<this._max )
                    {
                        lines.Add(this._max );
                    }
                }
                
            }


            int maxNumber = 15;

            if (isRound == false && lines != null)
            {
                maxNumber = 0;
                for (int i = 0; i < lines.Count; i++)
                {

                    int len = GetDecimalLengthInDoubleValue(lines[i]);

                    if (len > maxNumber)
                    {
                        maxNumber = len;
                    }
                }
            }
            noSpecificPrecision = maxNumber;



            //生成300个颜色集锦

            List<Color> rampColors = this.BuildColorRamp(this._rampColors, 300);

            foreach (double line in lines)
            {
                LinearContourColorValue cline = new LinearContourColorValue();
                if (isRound)
                {
                    cline.Value = Math.Round(line, precision);
                }
                else
                {
                    //cline.Value = line;
                    cline.Value = Math.Round(line, maxNumber );

                }
                //cline.Color = this.GetColor(line, rampColors);
                cline.Color = this.GetColor(cline.Value, rampColors);


                result.Add(cline);

            }




            if (isRound)
            {
                ChangeDataRange(result, precision);
            }
            else
            {
                ChangeDataRange(result, maxNumber);
            }

           


            //排序 去同

            return SortAndRemoveSameValue(result);


            //return result;

        }

        /// <summary>
        /// 修正最大最小值   例如：如果最小值是0.0000183  保留5位小数  四舍五入后是0.00002  比0.0000183要大，造成二维生成等值线的时候比0.00002小的值无法抽取等值线，着色等
        /// 这里要控制最小值的生成，例如如果最小值是0.0000183  要生成为如果最小值是0.00001  比0.0000183小
        /// 最大值类似，要往大的方向修正
        /// </summary>
        /// <param name="oldData"></param>
        ///  <param name="digitNum">使用的小数点位数</param>
        /// <returns></returns>
        private void ChangeDataRange(List<LinearContourColorValue> oldData, int digitNum)
        {
            if (oldData ==null )
            {
                return ;
            }

            if (oldData .Count >1)
            {
                //首先修改最小值
                for (int i = 0; true ; i++)
                {
                    if (oldData[0].Value > this._min)
                    {
                        double  dis = Math.Pow(10,-digitNum );

                        oldData[0].Value = oldData[0].Value - dis;

                        oldData[0].Value = Math.Round(oldData[0].Value,digitNum );
                        
                    }
                    else
                    {
                        break;
                    }
                }

                //修正最大值
                for (int i = 0; true; i++)
                {
                    if (oldData [oldData.Count -1].Value <this._max )
                    {

                        double dis = Math.Pow(10, -digitNum);

                        oldData[oldData.Count - 1].Value = oldData[oldData.Count - 1].Value + dis;

                        oldData[oldData.Count - 1].Value = Math.Round(oldData[oldData.Count - 1].Value, digitNum);
                        
                    }
                    else
                    {
                        break;
                    }
                
                    
                }

            }


            return ;
        
        }



        //计算等值线的一般算法描述

        //计算对应的具体等值线的值

        //取得rampColor 生成对应 的渐进颜色

        //根据对应的比例关系 ，截取对应的颜色

        /// <summary>
        /// 对数据List value 进行排序和去除相同的value值
        /// 从小到大
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private List<LinearContourColorValue> SortAndRemoveSameValue(List<LinearContourColorValue> value)
        {

            List<LinearContourColorValue> result = new List<LinearContourColorValue>();
            try
            {


                if (value != null)
                {

                    if (value.Count > 1)
                    {
                        //进行排序  因为数据量一般不会很大  可以选择冒泡排序法
                        //去掉  相等 的值 只留一个

                        for (int i = 0; i < value.Count; i++)
                        {
                            LinearContourColorValue temp = (LinearContourColorValue)value[i].Clone();


                            bool has = false;

                            for (int j = 0; j < result.Count; j++)
                            {

                                if (Math.Abs(result[j].Value - temp.Value) < 1e-8)
                                {
                                    has = true;
                                }

                            }
                            if (has == false)
                            {
                                result.Add(temp);
                            }

                        }
                        if (result.Count >= 2)
                        {
                            //冒泡排序 从小到大  大数后移的方法
                            for (int i = 0; i < result.Count; i++)
                            {
                                for (int j = 0; j < result.Count - i - 1; j++)
                                {

                                    if (result[j].Value > result[j + 1].Value)
                                    {
                                        LinearContourColorValue temp02 = (LinearContourColorValue)result[j].Clone();

                                        result[j] = (LinearContourColorValue)result[j + 1].Clone();


                                        result[j + 1] = (LinearContourColorValue)temp02.Clone();

                                    }


                                }

                            }
                        }


                    }
                    else if (value.Count==1)
                    {
                        return value;
                    }

                }



                return result;

            }
            catch
            {
                System.Windows.MessageBox.Show("抱歉，计算生成等值线过程出错！");
                result = new List<LinearContourColorValue>();
                return result;

            }
        }




        /// <summary>
        /// 取得double值的小数部分的长度
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private int GetDecimalLengthInDoubleValue(double value)
        {

            #region 以下的方法不可用，因为涉及到了double的加减等运算，有计算机内部存储数据的原理很容易知道，以下方法是多么的荒谬 哈哈

            //double  intValue = Math.Truncate(value );//取得double的整数部分

            //double decimalValue = 0;

            //if (intValue > value)
            //{
            //    decimalValue = intValue - value;

            //}
            //else if (intValue == value)
            //{
            //    return 0;
            
            //}
            //else 
            //{
            //    decimalValue = value - intValue;
            
            //}

            ////将小树部分转换成字符串计算长度
            //int strLength = decimalValue.ToString().Trim().Length;//0.0转成string后为 0  长度为1；  0  0.0   0.01   0.12345
            //if (strLength > 2)
            //{
            //    return strLength - 2;
            //}
            //else 
            //{
            //    return 0;

            //}

            #endregion

            //还是使用字符串来进行处理吧

            //value = 0.01;
            //value = 10.0;
            //value = 10;

            string[] ss = value.ToString().Split('.');

            int strLen = ss.Length;

            if (strLen > 1)
            {
                int len = ss[1].Length;

                if (len >6)
                {
                    //最多6位吧，再多也没有太大的意义，而且，double的精度也最多小数点后6位
                    return 6;
                }
                return len;
            }
            else 
            {
                return 0;
            }

         

        }



        //网络的一个小算法


        //COLOUR GetColour(double v, double vmin, double vmax)
        //{
        //    COLOUR c = { 1.0, 1.0, 1.0 }; // white
        //    double dv;

        //    if (v < vmin)
        //        v = vmin;
        //    if (v > vmax)
        //        v = vmax;
        //    dv = vmax - vmin;

        //    if (v < (vmin + 0.25 * dv))
        //    {
        //        c.r = 0;
        //        c.g = 4 * (v - vmin) / dv;
        //    }
        //    else if (v < (vmin + 0.5 * dv))
        //    {
        //        c.r = 0;
        //        c.b = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
        //    }
        //    else if (v < (vmin + 0.75 * dv))
        //    {
        //        c.r = 4 * (v - vmin - 0.5 * dv) / dv;
        //        c.b = 0;
        //    }
        //    else
        //    {
        //        c.g = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
        //        c.b = 0;
        //    }

        //    return (c);
        //}






    }
}
